package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面 用来实现 公共字段填充功能
 */
@Component
@Aspect
@Slf4j
public class AutoFillAspect {
    @Pointcut("@annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointcut(){}

    /**
     * 配置切面
     *    切入点+方位+增强代码
     */
    @Before("autoFillPointcut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("开始进行公共字段填充");
        //拦截住了 添加/修改 连接点

        // joinPoint 获取方法传递的参数
        Object[] args = joinPoint.getArgs();
        Object entry = args[0];//这是 新增 更新方法上传递的参数对象  (分类 员工 菜品 套餐 ...对象 )

        //1:判断 当前拦截住的连接点对应的方法是 更新 还是 添加
        // 基于 joinPoint获取到原始方法Method对象形式
        //1.1 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //1.2: 获取到原始方法Method
        Method method = signature.getMethod();
        //1.3 解析方法上的的注解
        AutoFill autoFill = method.getAnnotation(AutoFill.class);
        //1.4 获取注解中的操作类型
        OperationType operationType = autoFill.value();
        log.info("可以分辨自动填充操作类型:{}",operationType);

        //公共字段值 提取出来
        //登录人信息
        Long currentId = BaseContext.getCurrentId();
        //当前时间
        LocalDateTime now = LocalDateTime.now();

        log.info("即将实现公共字段填充...");
        //如果是更新 完成 两个字段的设置  将这两个字段设置 参数对象上
        if(operationType==OperationType.UPDATE){
            //更新-- 往参数对象设置两个属性 updateTime,updateUser
            //获取到 setUpateTime()方法的反射形式
            try {
                //更新时间
                Method setUpdateTime = entry.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                setUpdateTime.invoke(entry,now);
                //更新人
                Method setUpdateUser = entry.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setUpdateUser.invoke(entry,currentId);
            } catch (Exception e) {
                log.info("没有找到对应的set方法或无法运行");
                throw new RuntimeException(e);
            }


        }else{
            //新增-- 往参数对象设置四个属性  createTime,updateTime,createUser,updateUser
            try {
                //获取添加时间方法
                Method setCreateTime = entry.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                setCreateTime.invoke(entry,now);
                //更新时间
                Method setUpdateTime = entry.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                setUpdateTime.invoke(entry,now);
               //创建人
                Method setCreateUser = entry.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                setCreateUser.invoke(entry,currentId);
                //更新人
                Method setUpdateUser = entry.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setUpdateUser.invoke(entry,currentId);
            } catch (Exception e) {
                log.info("没有找到对应的set方法或无法运行");
                throw new RuntimeException(e);
            }
        }
    }
}
